package rua.jose.macamo;

import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

/**
 * The main activity of the application
 *
 */

public class Main extends MapActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
   //Map stuff
   private MapController mapController;
   private MapView mapView;

   //Location manager and listener
   private LocationManager locMgr;
   private LocListener locLtr;
   private CompassView compass;

   //Overlays
   private List<Overlay> mapOverlays;
   protected MyLocationOverlay me;

   private Resources res;
   protected SharedPreferences mPrefs;

   protected Drawable drawable;
   protected ItemizedOverlayArray items;

   /**
    * @see Activity.onCreate()
    */
   public void onCreate(final Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      res = getResources();

      initMap();
      initOverlays();
      initLocationManager();
      initMyLocation();

      mapOverlays.add(me);

      me.runOnFirstFix(new Runnable() {
         public void run() {
            mapController.setZoom(16);
            mapController.animateTo(me.getMyLocation());
         }
      });
      compass = (CompassView)findViewById(R.id.compassview);
      
      mPrefs = getSharedPreferences("TouristGuideSettings", Context.MODE_PRIVATE);
      mPrefs.registerOnSharedPreferenceChangeListener(this);
      onSharedPreferenceChanged(mPrefs, null);
   }
   

   @Override
   public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
      boolean compassEnabled = prefs.getBoolean("compass", true);
      if (compassEnabled)
         compass.setVisibility(View.VISIBLE);
      else
         compass.setVisibility(View.INVISIBLE);
      
      items.currentlyVisible.clear();
      if (prefs.getBoolean("attraction", true))
         items.addCategory(items.attraction);
      if (prefs.getBoolean("entertainment", true))
         items.addCategory(items.entertainment);
      if (prefs.getBoolean("sport", true))
         items.addCategory(items.sport);
      if (prefs.getBoolean("shopping", true))
         items.addCategory(items.shopping);
      if (prefs.getBoolean("restaurants", true))
         items.addCategory(items.restaurants);
      if (prefs.getBoolean("transportation", true))
         items.addCategory(items.transportation);
   }
   
   @Override
   public void onDestroy() {
      super.onDestroy();
      mPrefs.unregisterOnSharedPreferenceChangeListener(this);
      mPrefs = null;
      System.gc();
   }

   /**
    * Initializes ItemizedOvelayArray and adds mOverlayItems to it.
    */
   public void initOverlays(){
      mapOverlays = mapView.getOverlays();
      mapOverlays.clear();

      //default marker
      drawable = res.getDrawable(R.drawable.attraction);
      items = new ItemizedOverlayArray(drawable,this);
      
      //retrieve location data from XML
      boolean success = parseXML();
      if (!success) {
         Toast.makeText(this, "Could not parse xml, exiting", Toast.LENGTH_LONG).show();
         System.exit(-1);
      }
      mapOverlays.add(items); //Add items to the map
   }

   /**
    * Initializes MapView
    */
   public void initMap(){
      mapView = (MapView) findViewById(R.id.mapview);
      mapView.setBuiltInZoomControls(true);
      mapView.setStreetView(false);
      mapController = mapView.getController();
   }

   /**
    * Initializes MyLocationOverlay and stars listening for user location
    */
   public void initMyLocation(){
      me = new MyLocationOverlay(this, mapView){
         @Override
         public boolean onTap(final GeoPoint p, final MapView map) {
            return false;
         }
      };
      me.enableMyLocation();
   }

   /**
    * Initializes location manager and stars listening location from GPS and networks
    */
   public void initLocationManager(){
      locLtr = new LocListener(this);
      locMgr = (LocationManager) this.getSystemService(LOCATION_SERVICE);
      locMgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locLtr);
      locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locLtr);
   }

   /**
    * Parses locations and all other needed stuff from XML
    * @return true if parcing was successfull, otherwise false.
    */
   public boolean parseXML() {
      XMLHandlerLocation XMLHandler;
      //Parse through xml and save the stuff we need
      try {
         /** Handling XML */
         final SAXParserFactory spf = SAXParserFactory.newInstance();
         final SAXParser sp = spf.newSAXParser();
         final XMLReader xr = sp.getXMLReader();

         /** Create handler to handle XML Tags ( extends DefaultHandler ) */
         XMLHandler = new XMLHandlerLocation(items);
         xr.setContentHandler(XMLHandler);
         xr.parse(new InputSource(getResources().openRawResource(R.raw.maputo)));
      }catch (final Exception e) {
         System.out.println("XML Pasing Excpetion = " + e);
         return false;
      }
      return true;
   }

   @Override
   protected boolean isRouteDisplayed() {
      return false;
   }

   @Override
   public boolean onKeyDown(final int keyCode, final KeyEvent msg) {
      if(keyCode == KeyEvent.KEYCODE_BACK) {
         showDialog(-1);
         return true;
      }
      return false;
   }

   @Override
   public boolean onCreateOptionsMenu(final Menu menu) {
      final MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.menu, menu);
      return true;
   }

   @Override
   public boolean onOptionsItemSelected(final MenuItem item) {
      switch (item.getItemId()) {
         case R.id.settings:
            Intent settingsActivity = new Intent(getBaseContext(), TouristGuideSettings.class);
            startActivity(settingsActivity);
            break;
         case R.id.loc_list:
            final Intent intent = new Intent(Main.this, LocationList.class);
            intent.putParcelableArrayListExtra("items", items.all);
            startActivityForResult(intent, Constant.LIST_ITEM);
            break;
      }
      return true;
   }

   @Override
   protected Dialog onCreateDialog(final int id) {
      AlertDialog.Builder dlgAlert;
      dlgAlert = new AlertDialog.Builder(this);
      if (id == -1) {
         dlgAlert.setMessage("Are you sure you want to quit?");
         dlgAlert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(final DialogInterface dialog, final int id) {
               System.gc();
               System.exit(0);
            }
         });
         dlgAlert.setNegativeButton("No", new DialogInterface.OnClickListener() {
            public void onClick(final DialogInterface dialog, final int id) {
               System.gc();
            }
         });
         dlgAlert.setCancelable(false);
      }
      return dlgAlert.create();

   }

   protected void onActivityResult(final int requestCode, final int resultCode, final Intent data){
      if(requestCode == Constant.LIST_ITEM && resultCode != Constant.BACK){
         mOverlayItem item = items.all.get(resultCode);

         locLtr.setDestination(item);
         locLtr.showDistance();
         
         GeoPoint dest = item.getPoint();         
         //If the selected location is not visible, add it on map:
         if (!items.currentlyVisible.contains(item)) 
            items.addOverlay(item);
         mapController.setZoom(16);
         mapController.animateTo(dest);
         
         GeoPoint mee = me.getMyLocation();
         if (mee == null)
            return;
         double dlon = dest.getLongitudeE6()- mee.getLongitudeE6();
         double dlat = dest.getLatitudeE6() - mee.getLatitudeE6();
         //to degrees and add 180 degrees to compensate the orientation of the picture
         compass.angle = (float)Math.toDegrees((Math.atan2(dlat, dlon)))+180;

         
      }
   }
}